package algorithm.permutation;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

public class PermutationNonDuplicate {
    int[] dataArray;

    public PermutationNonDuplicate(int[] dataArray) {
        this.dataArray = dataArray;
    }

    public void visit(int length, Consumer<int[]> onVisit) {
        Map<Integer, Integer> countMap = Arrays.stream(dataArray).boxed().collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(it -> 1)));
        int[] visitedState = new int[countMap.size()];
        int[] newDataArray = new int[countMap.size()];
        int i = 0;
        for (Map.Entry<Integer, Integer> integerIntegerEntry : countMap.entrySet()) {
            newDataArray[i] = integerIntegerEntry.getKey();
            visitedState[i] = integerIntegerEntry.getValue();
            i++;
        }
        doVisit(newDataArray, length, onVisit, new int[dataArray.length], 0, visitedState);
    }

    private void doVisit(int[] dataArray, int length, Consumer<int[]> onVisit, int[] context, int validContextIndex, int[] visitedState) {
        if (validContextIndex == length) {
            onVisit.accept(Arrays.copyOf(context, length));
        } else {
            for (int i = 0; i < dataArray.length; i++) {
                if (visitedState[i] > 0) {
                    visitedState[i]--;
                    context[validContextIndex] = dataArray[i];
                    doVisit(dataArray, length, onVisit, context, validContextIndex + 1, visitedState);
                    visitedState[i]++;
                }
            }
        }
    }
}
